﻿#region Header Licence
//  NKnobMan, Copyright 2009, Alexandre MUTEL.
// 
//  This is free software; you can redistribute it and/or modify it
//  under the terms of the GNU Lesser General Public License as
//  published by the Free Software Foundation; either version 2.1 of
//  the License, or (at your option) any later version.
// 
//  This software is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//  Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public
//  License along with this software; if not, write to the Free
//  Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
//  02110-1301 USA, or see the FSF site: http://www.fsf.org.
#endregion
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace NKnobMan.Templatizer
{
    public partial class TemplatizerForm : KnobManFormBase, IProgressOnSaving
    {
        private KnobTemplate _knobTemplate;
        private readonly Bitmap _errorBitmap;
        private static Regex _invalidNames;
        private const string DefaultTitleBar = "NKnobMan Templatizer";
        private const string DefaultStatusBarForNew = "To start, select a Knob Input as a template...";
        private bool savedFromLastChange;
        private MruStripMenuInline _mruMenu;
        private KnobControl _previewKnobControl;

        public TemplatizerForm()
        {
            InitializeComponent();
            InitializeFromKnobMan();

            // Init default KnobTemplate instance
            _knobTemplate = new KnobTemplate();
            
            // Register for modified file
            _knobTemplate.PropertyChanged += _knobTemplate_PropertyChanged;

            _knobTemplate.Iterations.ListChanged += Iterations_ListChanged;

            // Initialize icon from the ErrorProvider icon
            _errorBitmap = errorProvider.Icon.ToBitmap();

            // Get invalid char for filenames
            _invalidNames = new Regex("[" + Regex.Escape(new string(Path.GetInvalidFileNameChars())) + "]");

            // Set status bar with no text
            toolStripStatusLabel.Text = DefaultStatusBarForNew;

            _mruMenu = new MruStripMenuInline(fileToolStripMenuItem, recentFileMenuItemToolStripMenuItem, MruClickedHandler, @"Software\NKnobMan\NKnobMan.Templatizer\MRU", true, 5);
            
            // ----------------------------------------------------------------------------------------------
            // Setup DataSources
            // ----------------------------------------------------------------------------------------------

            InitDataSources();
            BindDataSources();

            UpdateSavedState(true);
        }

        public void MruClickedHandler(int number, string filename)
        {
            if (File.Exists(filename))
            {
                LoadKnobFileTemplate(filename);
            }
        }

        void Iterations_ListChanged(object sender, ListChangedEventArgs e)
        {
            UpdateSavedState(false);
        }

        void _knobTemplate_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            UpdateSavedState(false);            
        }

        private void InitializeFromKnobMan()
        {
            if (KnobMan != null)
            {
                // labelHWND.Text = "Knobman Handle : " + KnobMan.Handle;
            }
        }

        private void UnBindSources()
        {
            // Bind DataSource for KnobTemplate
            // templateIterationBindingSource.DataSource = typeof(TemplateIteration);
            bindingSourceKnobTemplate.DataSource = typeof(KnobTemplate);
            ChangeBindingToTemplateOperations(typeof(TemplateOperation));
        }


        private void InitDataSources()
        {
            // Bind DataSource for Input and Preview combobox values
            inputDataGridViewTextBoxColumn.DataSource = KnobTemplateController.GetKnobParentItems();
            previewDataGridViewTextBoxColumn.DataSource = KnobTemplateController.GetPreviewMouseEventItems();
            comboBoxOutputAlignement.DataSource = KnobTemplateController.GetKnobOutputAlignement();
            // Bind DataSource for Operations combobox
            operationDataGridViewTextBoxColumn.DataSource = KnobTemplateController.GetTemplateOperationItems();

            templateIterationBindingSource.DataSource = bindingSourceKnobTemplate;
            templateIterationBindingSource.DataMember = "Iterations";
        }

        private void BindDataSources()
        {
            // Bind DataSource for KnobTemplate
            ChangeBindingToTemplateOperations(typeof (TemplateOperation));

            if (_knobTemplate.KnobInputPath != null)
            {
                LoadKnobFile();
                dataGridViewTemplateIteration.BackgroundColor = SystemColors.Window;
                dataGridViewTemplateOperation.BackgroundColor = SystemColors.Window;
            }
            else
            {
                // Init KNob with default operations
                _knobTemplate.InitWithDefaultOperations();

                dataGridViewTemplateIteration.BackgroundColor = SystemColors.Control;
                dataGridViewTemplateOperation.BackgroundColor = SystemColors.Control;

                // Enable Iterations and Operations
                splitContainerIterationsOperations.Enabled = false;
            }

            UpdatePanelPreviewGenerated();

            bindingSourceKnobTemplate.DataSource = _knobTemplate;
        }

        public void LoadKnobFile()
        {
            //// Update the preview image (if any)
            //pictureBoxPreview.Image = _knobTemplate.GetThumbnailForKnobInput();

            // Generate a default Template name


            try
            {
                // Open the knob file
                _knobTemplate.LoadKnobInput();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this,
                                "Unable to Load knob from " + _knobTemplate.KnobInputPath + ". Reason : " + ex,
                                "Error while loading knob", MessageBoxButtons.OK, MessageBoxIcon.Error);

                NewWithoutCheckingSavedState();
                return;
            }

            if (_knobTemplate.TemplateName == KnobTemplate.DefaultNamePrefix)
            {
                _knobTemplate.TemplateName = Path.GetFileNameWithoutExtension(_knobTemplate.KnobInputPath);
            }

            // Update Layer Paths
            layerDataGridViewTextBoxColumn.DataSource = KnobTemplateController.GetLayerItems(KnobMan.Default);

            object dataSourceForOperations = null;
            if (_knobTemplate.Iterations.Count > 0)
            {
                dataSourceForOperations = _knobTemplate.Iterations[0].Operations;
            }
            else
            {
                dataSourceForOperations = typeof(TemplateOperation);
            }
            ChangeBindingToTemplateOperations(dataSourceForOperations);

            // Enable Iterations and Operations
            splitContainerIterationsOperations.Enabled = true;

            toolStripStatusLabel.Text = "";
        }

        private bool bindingSourceTemplateOperationsDataSourceChanging = false;


        void ChangeBindingToTemplateOperations(object newDataSource)
        {
            bindingSourceTemplateOperationsDataSourceChanging = true ;
            bindingSourceTemplateOperations.DataSource = newDataSource;
            bindingSourceTemplateOperationsDataSourceChanging = false;
        }

        /// <summary>
        /// Handles the Click event of the buttonOpenKnobFile control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void buttonOpenKnobFile_Click(object sender, EventArgs e)
        {                       
            if ( openFileDialogKnobInput.ShowDialog(this) == DialogResult.OK )
            {
                    // Update the KnobInputPath
                    _knobTemplate.KnobInputPath = openFileDialogKnobInput.FileName;
         
                    LoadKnobFile();
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the checkBoxOutputPathAsInput control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void checkBoxOutputPathAsInput_CheckedChanged(object sender, EventArgs e)
        {
            if (!checkBoxOutputPathAsInput.Checked)
            {
                textBoxKnobOutputPath.Enabled = true;
                buttonOutputDirectory.Enabled = true;
            }
            else
            {
                textBoxKnobOutputPath.Enabled = false;
                buttonOutputDirectory.Enabled = false;
            }
        }

        /// <summary>
        /// Handles the Click event of the buttonOutputDirectory control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void buttonOutputDirectory_Click(object sender, EventArgs e)
        {
            if ( !string.IsNullOrEmpty(textBoxKnobInputPath.Text) )
            {
                // Use KnobInputPath as the default directory
                folderBrowserDialogOutputPath.SelectedPath = Path.GetDirectoryName(_knobTemplate.KnobInputPath);
            }

            // Open the folder browser dialog
            if ( folderBrowserDialogOutputPath.ShowDialog(this) == DialogResult.OK)
            {
                _knobTemplate.OutputPath = folderBrowserDialogOutputPath.SelectedPath;
            }
        }


        /// <summary>
        /// Handles the SelectionChanged event of the dataGridViewTemplateIteration control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void dataGridViewTemplateIteration_SelectionChanged(object sender, EventArgs e)
        {
            bool isRowSelected = dataGridViewTemplateIteration.CurrentRow != null;
            object dataSourceForOperations = typeof (TemplateOperation);
            if (isRowSelected && _knobTemplate.Iterations.Count > 0 )
            {
                int rowIndex = dataGridViewTemplateIteration.CurrentRow.Index;

                // Enable or disable Up Button for iterations
                toolStripButtonTemplateIterationUp.Enabled = rowIndex > 0 && rowIndex < _knobTemplate.Iterations.Count;

                // Enable or disable Down Button for iterations
                toolStripButtonTemplateIterationDown.Enabled = rowIndex >= 0 &&
                                                               rowIndex < (_knobTemplate.Iterations.Count - 1);

                // Set DataSource for operations on current selected Iteration
                dataSourceForOperations = _knobTemplate.Iterations[rowIndex].Operations;
            }

            // Bind DataSource for Operations
            ChangeBindingToTemplateOperations(dataSourceForOperations);

            // Enable Group Operations if a row is selected
            groupBoxOperations.Enabled = isRowSelected;
        }

        /// <summary>
        /// Handles the Click event of the toolStripButtonTemplateIterationUp control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void toolStripButtonTemplateIterationUp_Click(object sender, EventArgs e)
        {
            if ( toolStripButtonTemplateIterationUp.Enabled )
            {
                int position = templateIterationBindingSource.Position;
                if ( position == 0)
                    return;

                templateIterationBindingSource.RaiseListChangedEvents = false;

                TemplateIteration iteration = (TemplateIteration)templateIterationBindingSource.Current;
                position--;
                _knobTemplate.Move(iteration, position);
                templateIterationBindingSource.Position = position;
                templateIterationBindingSource.RaiseListChangedEvents = true;

                templateIterationBindingSource.ResetBindings(false);
            }
        }

        /// <summary>
        /// Handles the Click event of the toolStripButtonTemplateIterationDown control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void toolStripButtonTemplateIterationDown_Click(object sender, EventArgs e)
        {
            if (toolStripButtonTemplateIterationDown.Enabled)
            {
                int position = templateIterationBindingSource.Position;
                if (position == templateIterationBindingSource.Count - 1)
                    return;

                templateIterationBindingSource.RaiseListChangedEvents = false;
                TemplateIteration iteration = (TemplateIteration)templateIterationBindingSource.Current;
                position++;
                _knobTemplate.Move(iteration, position);
                templateIterationBindingSource.Position = position;
                templateIterationBindingSource.RaiseListChangedEvents = true;
                templateIterationBindingSource.ResetBindings(false);
            }
        }

        /// <summary>
        /// Handles the AddingNew event of the bindingSourceTemplateIteration control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.AddingNewEventArgs"/> instance containing the event data.</param>
        private void bindingSourceTemplateIteration_AddingNew(object sender, AddingNewEventArgs e)
        {
            e.NewObject = _knobTemplate.NewIteration();
        }

        /// <summary>
        /// Handles the CellValidating event of the dataGridViewTemplateIteration control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellValidatingEventArgs"/> instance containing the event data.</param>
        private void dataGridViewTemplateIteration_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            String errorText = null;
            if (dataGridViewTemplateIteration.Columns[e.ColumnIndex].Name == "nameDataGridViewTextBoxColumn")
            {
                if (e.FormattedValue != null && e.FormattedValue.ToString().Length > 0)
                {
                    foreach (DataGridViewRow row in dataGridViewTemplateIteration.Rows)
                    {
                        if (row.Index != e.RowIndex && row.Index < (dataGridViewTemplateIteration.Rows.Count - 1))
                        {
                            if (row.Cells[0].FormattedValue.Equals(e.FormattedValue))
                            {
                                errorText = "Iteration name must be unique. Name :[" + e.FormattedValue + "] is already used";
                                e.Cancel = true;
                            }
                        }
                    }
                } 
            }
            if ( errorText == null )
            {
                if (e.FormattedValue == null || e.FormattedValue.ToString().Length == 0)
                {
                    errorText = "Name cannot be empty";
                    e.Cancel = true;
                } else
                {
                    string name = e.FormattedValue.ToString();
                    if (IsInvalidName(name))
                    {
                        errorText = "Name must contain only valid filename characters";
                        e.Cancel = true;
                    }
                }
            }

            // Display an error if any
            if (errorText != null)
            {
                // Set Error Icon on status bar
                toolStripStatusLabel.Image = _errorBitmap;

                // Set Error Text on status bar
                toolStripStatusLabel.Text = errorText;

                // Set an error message on the row
                dataGridViewTemplateIteration.Rows[e.RowIndex].ErrorText = errorText; 
            }
        }

        /// <summary>
        /// Determines whether a name is valid.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>
        /// 	<c>true</c> if name is a valid name; otherwise, <c>false</c>.
        /// </returns>
        private bool IsInvalidName(string name)
        {
            return string.IsNullOrEmpty(name) || _invalidNames.IsMatch(name);
        }

        /// <summary>
        /// Handles the CellValidated event of the dataGridViewTemplateIteration control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellEventArgs"/> instance containing the event data.</param>
        private void dataGridViewTemplateIteration_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            toolStripStatusLabel.Text = string.Empty;
            toolStripStatusLabel.Image = null;
            dataGridViewTemplateIteration.Rows[e.RowIndex].ErrorText = string.Empty;
        }

        /// <summary>
        /// Handles the Click event of the viewDebugWindowToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void viewDebugWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            KnobManTraceListenerForm form = new KnobManTraceListenerForm();
            form.Icon = Icon;
            form.Show(this);
        }

        /// <summary>
        /// Handles the Validating event of the textBoxTemplateName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
        private void textBoxTemplateName_Validating(object sender, CancelEventArgs e)
        {
            string name = textBoxTemplateName.Text;
            if (IsInvalidName(name))
            {
                string errorText = "Name must be not empty and must contain valid chars for a filename";
                e.Cancel = true;
                errorProvider.SetError(textBoxTemplateName, errorText);
            }
        }

        /// <summary>
        /// Handles the Validated event of the textBoxTemplateName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void textBoxTemplateName_Validated(object sender, EventArgs e)
        {
            errorProvider.SetError(textBoxTemplateName, string.Empty);
        }

        /// <summary>
        /// Handles the KeyPress event of the textBoxTemplateName control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.KeyPressEventArgs"/> instance containing the event data.</param>
        private void textBoxTemplateName_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = false;
            if (e.KeyChar > ' ')
            {
                string name = "" + e.KeyChar;
                e.Handled = IsInvalidName(name);
            }
        }

        /// <summary>
        /// Handles the CellValueChanged event of the dataGridViewTemplateOperation control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellEventArgs"/> instance containing the event data.</param>
        private void dataGridViewTemplateOperation_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            // If layer or operation changed set default values using KnobMan current values
            if (e.ColumnIndex < 2  && e.RowIndex >= 0)
            {
                // Layer Value
                LayerEnum layerEnum = (LayerEnum)dataGridViewTemplateOperation.Rows[e.RowIndex].Cells[0].Value;
                string operation = (string)dataGridViewTemplateOperation.Rows[e.RowIndex].Cells[1].Value;

                if ( layerEnum != LayerEnum.All && ! string.IsNullOrEmpty(operation))
                {
                    int layerId = (int)layerEnum-1;
                    string value = KnobMan.Layers[layerId].GetValueFromPath(operation);
                    dataGridViewTemplateOperation.Rows[e.RowIndex].Cells[2].Value = value;
                }                
            }
        }

        /// <summary>
        /// Handles the CurrentCellDirtyStateChanged event of the dataGridViewTemplateOperation control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void dataGridViewTemplateOperation_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (dataGridViewTemplateOperation.CurrentCell.ColumnIndex < 2 && dataGridViewTemplateOperation.IsCurrentCellDirty)
            {
                dataGridViewTemplateOperation.CommitEdit(DataGridViewDataErrorContexts.Commit);
            }
        }

        /// <summary>
        /// Handles the Click event of the bindingNavigatorDeleteItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void bindingNavigatorDeleteItem_Click(object sender, EventArgs e)
        {
            DataGridViewRow currentRow = dataGridViewTemplateIteration.CurrentRow;
            bool deleteRow = true;

            if (currentRow != null && currentRow.Index < _knobTemplate.Iterations.Count )
            {
                if (_knobTemplate.Iterations[currentRow.Index].Operations.Count > 0)
                {
                    if (MessageBox.Show(this, "Are you sure?", "Delete row?", MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
                    {
                        deleteRow = false;
                    }
                }

                if (deleteRow)
                {
                    templateIterationBindingSource.RemoveAt(currentRow.Index);
                }
            }
        }

        private void buttonGenerate_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(this, "Are you sure?", DefaultTitleBar + " Generate", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
            {
                _knobTemplate.Generate(this);
                UpdatePanelPreviewGenerated();
            }
        }

        private void newTemplateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Check if file
            if (CheckIfNotSureWithFileNotSaved())
            {
                return;
            }
            NewWithoutCheckingSavedState();
        }

        private void NewWithoutCheckingSavedState()
        {
            UnBindSources();
            _knobTemplate.Reset();
            BindDataSources();
            UpdateSavedState(true);

            toolStripStatusLabel.Text = DefaultStatusBarForNew;
        }

        private bool CheckIfNotSureWithFileNotSaved()
        {
            return (!savedFromLastChange &&
                  MessageBox.Show(this, "Current template is not saved. Are you sure?", DefaultTitleBar,
                                  MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) ==
                  DialogResult.No
                 );
        }

        private void loadTemplateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ( openFileDialogKnobTemplate.ShowDialog(this) == DialogResult.OK  )
            {
                LoadKnobFileTemplate(openFileDialogKnobTemplate.FileName);
            }
        }

        private void LoadKnobFileTemplate(string fileName)
        {
            // Check if file
            if (CheckIfNotSureWithFileNotSaved())
            {
                return;
            }
            UnBindSources();
            _knobTemplate.Load(fileName);
            _mruMenu.AddFile(fileName, Path.GetFileName(fileName));
            BindDataSources();
            UpdateSavedState(true);            
        }

        private void saveTemplateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveKnobFileTemplate(false);
        }

        private void SaveKnobFileTemplate(bool saveAs)
        {
            string filePath = _knobTemplate.FilePath;
            if (filePath == null || !Directory.Exists(Path.GetDirectoryName(filePath)))
            {
                saveAs = true;
            }

            if (Directory.Exists(Path.GetDirectoryName(_knobTemplate.FilePath)))
            {
                saveFileDialogKnobTemplate.InitialDirectory = Path.GetDirectoryName(_knobTemplate.FilePath);
            }
            else if (Directory.Exists(Path.GetDirectoryName(_knobTemplate.KnobInputPath)))
            {
                saveFileDialogKnobTemplate.InitialDirectory = Path.GetDirectoryName(_knobTemplate.KnobInputPath);
            }

            if (saveAs && saveFileDialogKnobTemplate.ShowDialog(this) == DialogResult.OK)
            {
                filePath = saveFileDialogKnobTemplate.FileName;
            }

            if (filePath != null)
            {
                _knobTemplate.Save(filePath);
                _mruMenu.AddFile(filePath, Path.GetFileName(filePath));
                UpdateSavedState(true);
            }            
        }

        private void saveAsTemplateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveKnobFileTemplate(true);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void UpdateSavedState(bool savedFromLastChangeArg)
        {
            string titleBar = DefaultTitleBar;
            savedFromLastChange = savedFromLastChangeArg;

            if (_knobTemplate != null && _knobTemplate.FilePath != null)
            {
                titleBar += " - [" + Path.GetFileName(_knobTemplate.FilePath) + "]";
            }
            else
            {
                if (!savedFromLastChange)
                    titleBar += " - []";
            }

            if (!savedFromLastChange)
            {
                titleBar += "*";
            }
            Text = titleBar;
        }

        private void dataGridViewTemplateOperation_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
           Console.Out.WriteLine("Exception: " + e.Exception);
            e.ThrowException = true;
        }

        private void dataGridViewTemplateIteration_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            Console.Out.WriteLine("Exception: " + e.Exception);
            e.ThrowException = true;
        }

        private void bindingSourceTemplateOperations_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (!bindingSourceTemplateOperationsDataSourceChanging)
            {
                UpdateSavedState(false);
            }
        }

        private void templateIterationBindingSource_ListChanged(object sender, ListChangedEventArgs e)
        {
            UpdateSavedState(false);

            bool isGeneratePossible = (_knobTemplate != null && !string.IsNullOrEmpty(_knobTemplate.KnobInputPath) && _knobTemplate.Iterations.Count > 0);

            panelPreviewGenerated.Refresh();

            buttonGenerate.Enabled = isGeneratePossible;
            groupBoxPreview.Enabled = isGeneratePossible;
        }

        private void TemplatizerForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = CheckIfNotSureWithFileNotSaved();
            if (!e.Cancel)
            {
                _mruMenu.SaveToRegistry();
            }
        }

        public void InitProgress(string message, int maxStep)
        {
            Cursor = Cursors.WaitCursor;
            toolStripProgressBar.Minimum = 0;
            toolStripProgressBar.Maximum = maxStep;
            toolStripProgressBar.Value = 0;
            toolStripStatusLabel.Text = message;
            statusStripMain.Refresh();
        }

        public void Progress(string message, int step)
        {
            toolStripStatusLabel.Text = message;
            toolStripProgressBar.Value = step;
            statusStripMain.Refresh();
        }

        public void EndProgress()
        {
            Cursor = Cursors.Default;
            toolStripStatusLabel.Text = "";
            toolStripProgressBar.Value = 0;
            statusStripMain.Refresh();
        }

        int spaceBetween = 10;
        int nbPreview = 4;
        private Color previewBackColor = Color.Empty;

        private void UpdatePanelPreviewGenerated()
        {
            Size knobSize = _knobTemplate.KnobSize;

            nbPreview = NKnobMan.KnobMan.Default.PrefsPreviewFrames;

            int totalWidth = _knobTemplate.Iterations.Count * (knobSize.Width + spaceBetween);
            int totalHeight = nbPreview * (knobSize.Height + spaceBetween);
            if ( totalWidth < panelPreviewContainer.ClientSize.Width )
            {
                totalWidth = panelPreviewContainer.ClientSize.Width;
            }
            if ( totalHeight < panelPreviewContainer.ClientSize.Height )
            {
                totalHeight = panelPreviewContainer.ClientSize.Height;
            }

            panelPreviewGenerated.Size = new Size(totalWidth, totalHeight);  
            panelPreviewGenerated.Refresh();


            bool foundIterationBitmap = false;
            foreach (TemplateIteration iteration in _knobTemplate.Iterations)
            {
                if (iteration.GeneratedBitmap != null)
                {
                    foundIterationBitmap = true;
                    break;
                }
            }

            previewBackColor = KnobMan.Default.PrefsBackColor;

            if (!foundIterationBitmap)
            {
                labelGenerateForPreview.ForeColor = Color.Brown; 
                labelGenerateForPreview.Text = ">> Generate knobs to Preview and Test <<";
            } else
            {
                UpdateLabelForTestMode();
            }
        }

        private void UpdateLabelForTestMode()
        {
            labelGenerateForPreview.Text = "";
            if (radioButtonTestMouse.Checked)
            {
                toolStripStatusLabel.Text = "On Test Preview : " + toolTipMain.GetToolTip(radioButtonTestMouse);               
            } else
            {
                toolStripStatusLabel.Text = "";
            }
        }


        private void panelPreviewGenerated_Paint(object sender, PaintEventArgs e)
        {
            Size knobSize = _knobTemplate.KnobSize;

            SolidBrush textBrush = new SolidBrush(GetForeColorHighlight(previewBackColor));

            e.Graphics.FillRectangle(new SolidBrush(previewBackColor), panelPreviewGenerated.ClientRectangle);

            if (radioButtonPreview.Checked)
            {
                for (int i = 0; i < nbPreview; i++)
                {
                    Point startDraw = new Point(knobSize.Width/2 + spaceBetween,
                                                knobSize.Height / 2 + spaceBetween * 2 + i * (knobSize.Height + spaceBetween/2));


                    double ratio = (double) i/(nbPreview - 1);
                    foreach (TemplateIteration iteration in _knobTemplate.Iterations)
                    {
                        if (i == 0)
                        {
                            SizeF sizeOfText = e.Graphics.MeasureString(iteration.Name, Font);
                            e.Graphics.DrawString(iteration.Name, Font, textBrush,
                                                  new PointF(startDraw.X - sizeOfText.Width/2,
                                                             startDraw.Y - knobSize.Height/2 - spaceBetween/2 -
                                                             sizeOfText.Height));
                        }
                        if (iteration.GeneratedBitmap != null)
                        {
                            iteration.Draw(e.Graphics, startDraw, ratio);
                        }
                        startDraw.X = startDraw.X + (_knobTemplate.KnobSize.Width + spaceBetween);
                    }
                }
            }
        }

        private static Color GetForeColorHighlight(Color backColor)
        {
            HSBColor color = HSBColor.FromColor(backColor);
            return (color.B < 0.5) ? Color.White : Color.Black;
        }

        private void radioButtonTestMouse_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButtonTestMouse.Checked)
            {
                Color backColor = KnobMan.Default.PrefsBackColor;
                _previewKnobControl = new KnobControl(_knobTemplate, backColor, GetForeColorHighlight(backColor));
                _previewKnobControl.Visible = true;
                _previewKnobControl.Location = new Point(10, 0);
                panelPreviewGenerated.Controls.Add(_previewKnobControl);
                panelPreviewGenerated.Refresh();
            } else
            {
                if ( _previewKnobControl != null )
                {
                    panelPreviewGenerated.Controls.Remove(_previewKnobControl);
                    _previewKnobControl.Dispose();
                    _previewKnobControl = null;
                }
            }

            UpdateLabelForTestMode();
        }

        private void radioButtonPreview_CheckedChanged(object sender, EventArgs e)
        {
            panelPreviewGenerated.Refresh();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.ShowDialog(this);
        }

        private void showHelpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start("http://nknobman.codeplex.com", null);
        }

    }
}
